#pragma once
#include"data.hpp"
#include"util.hpp"
#include"httplib.h"
#include <windows.h>

namespace CH
{
#define SERVER_IP "115.159.87.192"
#define SERVER_PORT 8080
	class Backup
	{
	private:
		std::string _back_dir;//备份目录，也就是要上传文件的目录
		DataManager* _data;//管理文件
	public:
		Backup(const std::string& back_dir,const std::string& back_up)
			:_back_dir(back_dir)
		{
			_data = new DataManager(back_up);
		}
		bool RunModule()
		{
			while (true)
			{
				//遍历备份目录的文件，将其存入数组
				FileUtil fu(_back_dir);
				std::vector<std::string> arry;
				fu.ScanDirectory(&arry);

				//对于这些文件，逐个判断是否要上传
				for (auto& a : arry)
				{
					if (IsNeedUpload(a) == false) {
						continue;
					}

					//文件需要上传
					if (Upload(a) == true) {
						_data->Insert(a, GetFileETag(a));//新增文件备份信息
						std::cout << a << " upload success!\n";
					}
				}
				Sleep(2000);
			}
		}

		//根据文件名，获取文件的唯一值
		std::string GetFileETag(const std::string& filename)
		{
			// a.txt-fsize-mtime
			FileUtil fu(filename);
			std::stringstream ss;
			ss << fu.FileName() << "-" << fu.FileSize() << "-" << fu.LastMTime();
			return ss.str();
		}

		//判断文件是否要上传
		bool IsNeedUpload(const std::string& filename)
		{
			// 需要上传的文件的判断条件：文件是新增的，不是新增但是被修改过
			// 文件是新增的：看一下有没有历史备份信息
			// 不是新增但是被修改过：有历史信息，但是历史的唯一标识与当前最新的唯一标识不一致
			std::string etag;//保存旧的唯一值
			if (_data->GetOneByKey(filename,&etag) != false)
			{
				//获取该文件新的唯一值
				std::string new_etag = GetFileETag(filename);
				if (etag == new_etag) {//相同，则表示没有被修改过
					return false;
				}
			}

			//一个文件比较大,正在徐徐的拷贝到这个目录下，拷贝需要一个过程，
			//如果每次遍历则都会判断标识不一致需要上传一个几十G的文件会上传上百次
			//因此应该判断一个文件一段时间都没有被修改过了，则才能上传
			FileUtil fu(filename);
			if (time(NULL) - fu.LastMTime() < 3) {//3秒钟之内刚修改过--认为文件还在修改中
				return false;
			}
			std::cout << filename << " need upload!\n";
			return true;
		}

		//上传文件
		bool Upload(const std::string& filename)
		{
			//获取该文件的所有数据
			FileUtil fu(filename);
			std::string body;
			fu.GetContent(&body);

			//搭建客户端上传文件数据
			httplib::Client client(SERVER_IP, SERVER_PORT);			//创建客户端
			httplib::MultipartFormData item;						//创建字段
			item.content = body;//设置该字段携带文件的内容
			item.filename = fu.FileName();//设置携带文件名
			item.name = "file";										//设置字段名，这是和服务器约定好的
			item.content_type = "application/octet-stream";
			httplib::MultipartFormDataItems items;
			items.push_back(item);

			auto res = client.Post("/upload", items);
			if (!res || res->status != 200) {
				return false;
			}
			return true;
		}
	};
}